package com.yhy.wxzn.wcs.device.plc.xj;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.yhy.wxzn.common.enums.HoistStatus;
import com.yhy.wxzn.common.enums.WcsDeviceTypeEnums;
import com.yhy.wxzn.common.utils.WcsUtils;
import com.yhy.wxzn.wcs.entity.WcsDeviceInfo;
import com.yhy.wxzn.wcs.enums.TaskStatus;
import com.yhy.wxzn.common.enums.WcsTaskTypeEnums;
import com.yhy.wxzn.common.exception.WmsBusinessException;
import com.yhy.wxzn.common.utils.ListHelper;
import com.yhy.wxzn.common.utils.SpringUtil;
import com.yhy.wxzn.wcs.device.plc.bean.BasePlc;
import com.yhy.wxzn.wcs.entity.WcsElevatorTask;
import com.yhy.wxzn.wcs.device.plc.bean.HoistPlc;
import com.yhy.wxzn.wcs.device.plc.bean.TransmissionPlc;
import com.yhy.wxzn.wcs.service.IWcsDeviceInfoService;
import com.yhy.wxzn.wcs.service.IWcsDeviceLogService;
import com.yhy.wxzn.wcs.service.IWcsElevatorTaskService;
import com.yhy.wxzn.wcs.utils.PlcUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Auther: 97354
 * @Date: 2023/11/6 16:16
 * @Description: SiemensHoistProtocol
 * @Version 1.0.0
 */
@Slf4j
public class XjHoistProtocol extends Thread {

    private volatile String plcName;
    private volatile WcsDeviceInfo hoist;
    public volatile XjPlcDriver xjPlcDriver;
    private IWcsElevatorTaskService elevatorTaskService;
    private IWcsDeviceLogService deviceLogService;
    private IWcsDeviceInfoService deviceInfoService;

    public XjHoistProtocol(String plcName,WcsDeviceInfo hoist,XjPlcDriver xjPlcDriver) {
        this.plcName = plcName;
        this.hoist = hoist;
        this.xjPlcDriver = xjPlcDriver;
    }

    private void init() {
        elevatorTaskService = SpringUtil.getBean(IWcsElevatorTaskService.class);
        deviceLogService = SpringUtil.getBean(IWcsDeviceLogService.class);
        deviceInfoService = SpringUtil.getBean(IWcsDeviceInfoService.class);
    }

    @Override
    public void run() {
        //等待Spring 容器加载完成
        while (true) {
            try {
                if (SpringUtil.getApplicationContext() != null) {
                    init();
                    break;
                }
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        while (true) {
            try {
                if (!xjPlcDriver.xjHelper.isConnectd()) {
                    sleep(10000);
                    continue;
                }
                //提升机出入库业务逻辑
                hoistProcess();
                sleep(100);
            } catch (Exception e) {
                WcsUtils.sleep(1000);
                log.error("提升机任务处理异常", e);
            }
        }
    }

    private void hoistProcess() {
        try {
            if (!CollectionUtils.isEmpty(xjPlcDriver.getDriverData().getHoistPlcMap())) {
                xjPlcDriver.getDriverData().getHoistPlcMap().entrySet().parallelStream().forEach(hoistEntry -> {
                    List<WcsElevatorTask> mcsTaskInfoList = elevatorTaskService.getUnfinishedByHoistList();
                    if (CollectionUtils.isEmpty(mcsTaskInfoList)) {
                        return;
                    }
                    HoistPlc hoistPlc = hoistEntry.getValue();
                    if (null == hoistPlc) {
                        return;
                    }
                    //任务开始
                    startHoistTask(mcsTaskInfoList, hoistPlc);
                    //任务结束
                    finishHoistTask(mcsTaskInfoList, hoistPlc);



                    //任务下发
                    sendHoistTask(mcsTaskInfoList, hoistPlc);
                });
            }
        } catch (Exception ex) {
            log.error("hoistProcess 异常", ex);
        }
    }

    private void sendHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) && TaskStatus.READY.getTaskProgress() == t.getTaskStatus()
        );
        //无任务
        if (null == mcsTaskInfo) {
            return;
        }
        String targetCoord = mcsTaskInfo.getTarget();
        int targetFloor = Integer.valueOf(targetCoord.substring(0, 2));
        /**
         * 判断当前提升机和任务要求到达层是否一致
         * 1:一致直接完成任务
         * 2：不一致需调度小车生成跨层任务
         * */
        if (hPlc.getFloor() == targetFloor) {
            if (!(TaskStatus.FINISH.getTaskProgress() == mcsTaskInfo.getTaskStatus())) {
                mcsTaskInfo.setTaskStatus(TaskStatus.FINISH.getTaskProgress());
                mcsTaskInfo.setFinishTime(new Date());
                elevatorTaskService.updateById(mcsTaskInfo);
                return;
            }
        } else {
            try {
                //信号检查
                hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getSource(), TaskStatus.READY.getTaskProgress());
                //写PLC指令
                mcsWritePlc(mcsTaskInfo);
                hPlc.setLocking(1);
                //改任务状态为已下发
                mcsTaskInfo.setTaskStatus(TaskStatus.SEND.getTaskProgress());
                mcsTaskInfo.setSendTime(new Date());
                mcsTaskInfo.setRemark("");
                elevatorTaskService.updateById(mcsTaskInfo);
                //任务日志
                String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
                String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务下发PLC成功, 提升机 " + hPlc.getHoistId() + mcsTaskInfo.getSource() + ">>" + mcsTaskInfo.getTarget();
                String content = "【" + desc + "】" + msg;
                deviceLogService.genCoordLog(hPlc.getHoistId(), content);
            } catch (WmsBusinessException e) {
                overTask(mcsTaskInfo, e.getMessage());
            }
        }
    }

    private void mcsWritePlc(WcsElevatorTask mcsTaskInfo) {
        WcsTaskTypeEnums taskType = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType());
        switch (Objects.requireNonNull(taskType)) {
            case INBOUND_H:
            case INBOUND_HC:
            case OUTBOUND_HC:
            case OUTBOUND_H:
                mcsWriteHoistPlc(mcsTaskInfo);
                break;
            default:
                log.error(String.format("任务类型%s不存在", mcsTaskInfo.getTaskType()));
                throw new WmsBusinessException("未知的任务类型");
        }
    }

    private void mcsWriteHoistPlc(WcsElevatorTask mcsTaskInfo) {
        BasePlc sourcePlc = getPlcPropertyByCoordAndType(mcsTaskInfo.getSource(), WcsDeviceTypeEnums.ELV.getCode());
        if (null == sourcePlc) {
            throw new WmsBusinessException(String.format("%s PLC读值地址不存在，请检查配置", mcsTaskInfo.getSource()));
        }
        BasePlc targetPlc = getPlcPropertyByCoordAndType(mcsTaskInfo.getTarget(), WcsDeviceTypeEnums.ELV.getCode());
        if (null == targetPlc) {
            throw new WmsBusinessException(String.format("%s PLC读值地址不存在，请检查配置", mcsTaskInfo.getTarget()));
        }
        int sourceFloor = Integer.parseInt(mcsTaskInfo.getSource().substring(0, 2));
        int sourceDevice = sourcePlc.getStation();
        int targetFloor = Integer.parseInt(mcsTaskInfo.getTarget().substring(0, 2));
        int targetDevice = targetPlc.getStation();
        int type;

        WcsTaskTypeEnums taskType = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType());
        switch (Objects.requireNonNull(taskType)) {
            case INBOUND_H:
                type = 1;
                break;
            case OUTBOUND_H:
                type = 2;
                break;
            default:
                type = 3;
        }
        boolean result = writeHoistPlcAddress(
                mcsTaskInfo.getTaskNo(),
                sourcePlc.getWriteAddress(),
                sourceFloor,
                sourceDevice,
                targetFloor,
                targetDevice,
                type,
                0
                //mcsTaskInfo.getSerialNo()
        );
        if (!result) {
            throw new WmsBusinessException("PLC写入失败，请查看PLC日志");
        }
    }

    private BasePlc getPlcPropertyByCoordAndType(String coordInput, String typeInput) {
        if (WcsDeviceTypeEnums.TSL.getCode().equals(typeInput)) {
            //获取输送线点位
            if (!CollectionUtils.isEmpty(xjPlcDriver.getDriverData().getTransLinePlcMap())) {
                return xjPlcDriver.getDriverData().getTransLinePlcMap().get(coordInput);
            }
        } else if (WcsDeviceTypeEnums.ELV.getCode().equals(typeInput)) {
            //获取提升机点位
            if (!CollectionUtils.isEmpty(xjPlcDriver.getDriverData().getCoordPlcMap())) {
                return xjPlcDriver.getDriverData().getCoordPlcMap().get(coordInput);
            }
        }
        return null;
    }

    private boolean writeHoistPlcAddress(String taskNo, String address, int sourceFloor, int sourceDevice, int targetFloor, int targetDevice, int type, int mcsId) {
    //todo 改。。
        //        byte[] bytes = PlcUtils.taskHoistByte(sourceFloor, sourceDevice, targetFloor, targetDevice, type, mcsId);
//        Map<String, Object> map = Maps.newHashMap();
//        map.put("起始层", sourceFloor);
//        map.put("起始工位", sourceDevice);
//        map.put("目标层", targetFloor);
//        map.put("目标工位", targetDevice);
//        map.put("任务类型", type);
//        map.put("任务号", mcsId);
//        map.put("Wms任务号", taskNo);
//        return xjPlcDriver.savePlcLog(address, bytes, map);
        return true;
    }

    private void finishHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        //检查任务结束
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) &&
                        ArrayUtils.contains(new int[]{TaskStatus.SEND.getTaskProgress(), TaskStatus.START.getTaskProgress()}, t.getTaskStatus()));
        if (null == mcsTaskInfo) {
            return;
        }
        String taskJsonLog = JSON.toJSONString(mcsTaskInfo);
        try {
            //信号检查
            hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getTarget(), TaskStatus.START.getTaskProgress());
            hPlc.setLocking(0);
            log.info("{}提升机解锁，提升机任务完成，任务信息：{}", hPlc.getHoistId(), taskJsonLog);
            //修改任务状态为完成
            mcsTaskInfo.setTaskStatus(TaskStatus.FINISH.getTaskProgress());
            mcsTaskInfo.setFinishTime(new Date());
            mcsTaskInfo.setRemark("");
            elevatorTaskService.updateById(mcsTaskInfo);
            log.info("{}任务回告完成，更新任务状态为3，任务信息：{}", mcsTaskInfo.getTaskNo(), taskJsonLog);
            //任务日志
            String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务完成，提升机 " + hPlc.getHoistId() + " 当前层=" + hPlc.getFloor();
            String content = "【" + desc + "】" + msg;
            deviceLogService.genCoordLog(hPlc.getHoistId(), content);
        } catch (WmsBusinessException e) {
            //log.warn("{}有已开始的任务，{}，任务信息：{}", getHoistId(), e.getMessage(), taskJsonLog);
            overTask(mcsTaskInfo, e.getMessage());
        }
    }

    private void startHoistTask(List<WcsElevatorTask> mcsTaskInfoList, HoistPlc hPlc) {
        //检查任务开始
        WcsElevatorTask mcsTaskInfo = ListHelper.firstOrDefault(mcsTaskInfoList, t ->
                hPlc.getHoistId().equals(t.getDeviceCode()) && TaskStatus.SEND.getTaskProgress() == t.getTaskStatus()
        );
        if (null == mcsTaskInfo) {
            return;
        }
        String taskJsonLog = JSON.toJSONString(mcsTaskInfo);
        try {
            //信号检查
            hoistTaskCheck(hPlc, mcsTaskInfo, mcsTaskInfo.getSource(), TaskStatus.SEND.getTaskProgress());
            mcsTaskInfo.setTaskStatus(TaskStatus.START.getTaskProgress());
            mcsTaskInfo.setStartTime(new Date());
            mcsTaskInfo.setRemark("");
            elevatorTaskService.updateById(mcsTaskInfo);
            log.info("{}任务回告开始，更新任务状态为2，任务信息：{}", mcsTaskInfo.getTaskNo(), taskJsonLog);
            //任务日志
            String desc = WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()) != null ? WcsTaskTypeEnums.ofValue(mcsTaskInfo.getTaskType()).getDesc() : "未知";
            String msg = mcsTaskInfo.getPalletNo() + " " + desc + "任务开始，提升机 " + hPlc.getHoistId() + " 当前层=" + hPlc.getFloor();
            String content = "【" + desc + "】" + msg;
            deviceLogService.genCoordLog(hPlc.getHoistId(), content);
        } catch (WmsBusinessException e) {
            overTask(mcsTaskInfo, e.getMessage());
        }
    }

    private void overTask(WcsElevatorTask mcsTaskInfo, String msg) {
        if (msg.equals(mcsTaskInfo.getRemark())) {
            return;
        }
        mcsTaskInfo.setRemark(msg);
        elevatorTaskService.updateById(mcsTaskInfo);
    }

    //nb
    private void hoistTaskCheck(HoistPlc hPlc, WcsElevatorTask mcsTaskInfo, String coord, int status) {
        //int mcsId = mcsTaskInfo.getSerialNo();
//        //提升机信号检查
//        WcsDeviceInfo mcsHoist = xjPlcDriver.plcDataPacket.getDevicePlcMap().get(hPlc.getHoistId());
        if (null == hPlc) {
            throw new WmsBusinessException(String.format("%s 未初始化，请检查配置", hPlc.getHoistId()));
        }
        if (!hPlc.isAuto()) {
            throw new WmsBusinessException(String.format("%s 不是自动状态，等待系统切换为自动状态", hPlc.getHoistId()));
        }
        if (HoistStatus.Auto.getValue() != hPlc.getAutoStatus()) {
            throw new WmsBusinessException(String.format("%s 不是联机自动状态，等待设备切换为联机自动状态", hPlc.getHoistId()));
        }
        //输送线信号检查
        TransmissionPlc tPlc = (TransmissionPlc) getPlcPropertyByCoordAndType(coord, WcsDeviceTypeEnums.TSL.getCode());
        if (null == tPlc) {
            throw new WmsBusinessException(String.format("%s 未初始化，请检查配置", coord));
        }
        if (!tPlc.isAuto()) {
            throw new WmsBusinessException(String.format("%s 不是自动状态，等待系统切换为自动状态", tPlc.getStation()));
        }
        if (tPlc.getStatus() != 2) {
            throw new WmsBusinessException(String.format("%s 不是联机自动状态，等待设备切换为联机自动状态", tPlc.getStation()));
        }
        if (TaskStatus.SEND.getTaskProgress() == status) {
            //任务开始检查
            if (tPlc.getInPlaceNum() == 1) {
                throw new WmsBusinessException(String.format("%s 有载位信号，等待容器进提升机", tPlc.getStation()));
            }
//            if (tPlc.getDeviceNum() == mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号未清空，等待容器进提升机", tPlc.getStation()));
//            }
            if (hPlc.isHaveStock()) {
                throw new WmsBusinessException(String.format("%s 轿厢无货，请检查容器/光电是否正常", hPlc.getHoistId()));
            }
            if (hPlc.isHaveCar()) {
                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
            }
//            if (hPlc.getTaskId() != mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号%s与MCS任务号%s不一致，等待容器进入轿厢", hPlc.getHoistId(), hPlc.getTaskId(), mcsId));
//            }
        } else if (TaskStatus.START.getTaskProgress() == status) {
            //任务完成检查
            if (tPlc.getInPlaceNum() == 0) {
                throw new WmsBusinessException(String.format("%s 无载位信号，等待容器送达", tPlc.getStation()));
            }
//            if (tPlc.getDeviceNum() != mcsId) {
//                throw new WmsBusinessException(String.format("%s PLC任务号%s与MCS任务号%s不一致，等待容器送达", tPlc.getStation(), tPlc.getDeviceNum(), mcsId));
//            }
            if (hPlc.isHaveStock()) {
                throw new WmsBusinessException(String.format("%s 轿厢有货，请检查容器/光电是否正常", hPlc.getHoistId()));
            }
            if (hPlc.isHaveCar()) {
                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
            }
        } else if (TaskStatus.READY.getTaskProgress() == status) {
            //任务下发检查
            if (tPlc.getInPlaceNum() == 0) {
                throw new WmsBusinessException(String.format("%s 无载位信号，请检查容器/光电是否正常", tPlc.getStation()));
            }
            if (hPlc.getWorkStatus() != 1) {
                throw new WmsBusinessException(String.format("%s 不是就绪状态，等待设备就绪", hPlc.getHoistId()));
            }
            if (hPlc.getLocking() == 1) {
                throw new WmsBusinessException(String.format("%s 暂时锁定，等待提升机解锁", hPlc.getHoistId()));
            }
            if (hPlc.isHaveStock()) {
                throw new WmsBusinessException(String.format("%s 轿厢有货，请检查容器/光电是否正常", hPlc.getHoistId()));
            }
            if (hPlc.isHaveCar()) {
                throw new WmsBusinessException(String.format("%s 轿厢有车，请检查小车/光电是否正常", hPlc.getHoistId()));
            }
        }
    }
}
